#include "flash-board.h"
#include "system.h"



int FlashRead(uint32_t address, uint8_t *pBuffer, uint16_t readNum)
{
	uint16_t i;
    uint32_t readAddr = address;

	for(i = 0; i < readNum; i++)
	{
		pBuffer[i] = *(uint8_t*)(readAddr + i);
	}
	return 0;
}

int FlashWrite(uint32_t address, uint8_t *pBuffer, uint16_t writeNum)
{
	uint16_t i;
    uint32_t writeAddr = address;

	for(i = 0; i < writeNum; i++)
	{
		*(uint8_t*)(writeAddr + i) = pBuffer[i];
	}
	return 0;
}

void FlashInit(void)
{

}

int EepromSave(uint32_t writeAddress,uint8_t* writeBuffer, uint16_t writeNum)
{
    uint16_t i = 0;
    if((writeAddress < FLASH_BASE) || ((writeAddress + writeNum) > (FLASH_BASE + CHIP_FLASH_SIZE)))
    {
        return -1;
    }
    return FlashWrite(writeAddress, writeBuffer, writeNum); 
}

int EepromReadData(uint32_t ReadAddress,uint8_t* readBuffer, uint16_t readNum)
{
    uint16_t i = 0;
    if((ReadAddress < FLASH_BASE) || ((ReadAddress + readNum) > (FLASH_BASE + CHIP_FLASH_SIZE)))
    {
        return -1;
    }
    return FlashRead(ReadAddress,readBuffer,readNum); 
}

#if defined(CONFIG_FLASH_PROCESS_RAM)
volatile uint8_t FlashBuffer[FLASH_PAGE_SIZE] = {0};
int EepromWriteData(uint32_t writeAddress,uint8_t* writeBuffer, uint16_t writeNum)
{
	uint32_t secpos = 0;	   	//扇区地址
	uint16_t secoff = 0;	   	//扇区内偏移地址(16位字计算)
	uint16_t secremain = 0; 	//扇区内剩余地址
 	uint16_t i = 0;
	uint32_t offaddr = 0;   	//去掉0X08000000后的地址
    uint32_t falshPageSize = 0;
    uint32_t writePageAddr = 0;

    if((writeAddress < FLASH_BASE) || ((writeAddress + writeNum) > (FLASH_BASE + CHIP_FLASH_SIZE)))
    {
        return -1;
    }

	__disable_irq();

    while(1)
	{
        writeBuffer += secremain;  	                //指针偏移
        writeAddress += secremain;	                //写地址偏移
        writeNum -= secremain;	                	//字节数递减

		offaddr = writeAddress - FLASH_BASE;		//实际偏移地址
		falshPageSize = FLASH_PAGE_SIZE;
		
		secpos = offaddr/falshPageSize;				//扇区地址
		secoff = (offaddr%falshPageSize);			//在扇区内的偏移
		secremain = falshPageSize - secoff;			//扇区剩余空间大小
		writePageAddr = FLASH_BASE + secpos*falshPageSize;
    
        
        if(writeNum <= secremain)             		//写的数据不大于改扇区的大小，也就没有跨扇区
        {
            secremain = writeNum;
        }
        
		FlashRead(writePageAddr,(void *)FlashBuffer,falshPageSize);//读出整个扇区的内容
		for(i = 0;i < falshPageSize;i++)            //校验数据
		{
			if(FlashBuffer[i] != 0XFF)              //需要擦除
			{
				break;
			}
		}
		if(i < falshPageSize)                       //需要擦除
		{
			if(flash_erase_page(writePageAddr) != ERRNO_OK)        //擦除flash扇区
			{
				LOG_PRINTF(LL_DEBUG,"flash_erase_page error\r\n");
				return -1;
			}
           
			for(i=0;i < secremain;i++)          	//复制数据
			{
				FlashBuffer[i+secoff]=writeBuffer[i];
			}

			if(flash_program_bytes(writePageAddr,(void *)FlashBuffer,falshPageSize) != ERRNO_OK)
			{
				LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
				return -1;
			}
		}
        else
		{
            for(i=0;i < secremain;i++)          	//复制数据
			{
				FlashBuffer[i+secoff]=writeBuffer[i];
			}

			if(flash_program_bytes(writePageAddr,(void *)FlashBuffer,falshPageSize) != ERRNO_OK)
			{
				LOG_PRINTF(LL_DEBUG,"flash_program_bytes2 error\r\n");
				return -1;
			}
		}

		if(writeNum == secremain)               	//写入结束
		{
			break;
		}
	}

	__enable_irq();

}

#endif


#if defined(CONFIG_FLASH_PROCESS_FLASH)
int EepromWriteData(uint32_t writeAddress,uint8_t* writeBuffer, uint16_t writeNum)
{
	uint32_t secpos = 0;	   	//扇区地址
	uint16_t secoff = 0;	   	//扇区内偏移地址(16位字计算)
	uint16_t secremain = 0; 	//扇区内剩余地址
 	uint32_t i = 0;
	uint32_t offaddr = 0;   	//去掉0X08000000后的地址
    uint32_t falshPageSize = 0;
    uint32_t writePageAddr = 0;
	uint32_t writeAddr = 0;
	uint32_t readAddr = 0;
	uint8_t buffer[16] = {0};

    if((writeAddress < FLASH_BASE) || ((writeAddress + writeNum) > (FLASH_BASE + CHIP_FLASH_SIZE)))
    {
		LOG_PRINTF(LL_DEBUG,"EepromWriteData:addr=0x%0x error\r\n",writeAddress);
        return -1;
    }

	while(1)
	{
		writeBuffer += secremain;  	                //指针偏移
        writeAddress += secremain;	                //写地址偏移
        writeNum -= secremain;	                	//字节数递减

		/*****擦除备份区*****/
		if(flash_erase_page(FLASH_PROCESS_BACKUP_ADDR) != ERRNO_OK)        //擦除备份flash扇区
		{
			LOG_PRINTF(LL_DEBUG,"flash erase backup error\r\n");
			return -1;
		}

		/*****将需要写入数据的区域搬迁到备份区，并擦除需要写入数据的区域*****/ 
		offaddr = writeAddress - FLASH_BASE;		//实际偏移地址
		falshPageSize = FLASH_PAGE_SIZE;
		
		secpos = offaddr/falshPageSize;				//扇区地址
		secoff = (offaddr%falshPageSize);			//在扇区内的偏移,即需要写数据的位置
		secremain = falshPageSize - secoff;			//扇区剩余空间大小
		writePageAddr = FLASH_BASE + secpos*falshPageSize;	//获取到需要写的页起始地址
		
		if(writeNum <= secremain)             		//写的数据不大于改扇区的大小，也就没有跨扇区
        {
            secremain = writeNum;
        }

		writeAddr = writePageAddr;
		for(i = 0; i < FLASH_PAGE_SIZE; i += sizeof(buffer))	//进行flash数据搬迁到备份区域
		{
			memset(buffer,0,sizeof(buffer));
			FlashRead(writeAddr,(void *)buffer,sizeof(buffer));//读出整个扇区的内容

			if(flash_program_bytes(writeAddr,(void *)buffer,sizeof(buffer)) != ERRNO_OK)
			{
				LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
				return -1;
			}

			writeAddr += sizeof(buffer);
		}

		if(flash_erase_page(writePageAddr) != ERRNO_OK)        //擦除需要写的区域
		{
			LOG_PRINTF(LL_DEBUG,"flash erase flash error\r\n");
			return -1;
		}

		/*****将需要写入的数前的内容从备份区搬迁到主区*****/ 
		writeAddr = writePageAddr;
		readAddr = FLASH_PROCESS_BACKUP_ADDR;
		for(i = 0; i < secoff/sizeof(buffer); i++)			//将备份区的数据拷贝到主区
		{
			memset(buffer,0,sizeof(buffer));
			FlashRead(readAddr,(void *)buffer,sizeof(buffer));	//读出整个扇区的内容

			if(flash_program_bytes(writeAddr,(void *)buffer,sizeof(buffer)) != ERRNO_OK)
			{
				LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
				return -1;
			}

			readAddr += sizeof(buffer);
			writeAddr += sizeof(buffer);
		}
		if(secoff%sizeof(buffer) != 0)
		{
			memset(buffer,0,sizeof(buffer));
			FlashRead(readAddr,(void *)buffer,secoff%sizeof(buffer));	//读出整个扇区的内容

			if(flash_program_bytes(writeAddr,(void *)buffer,secoff%sizeof(buffer)) != ERRNO_OK)
			{
				LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
				return -1;
			}

			readAddr += secoff%sizeof(buffer);
			writeAddr += secoff%sizeof(buffer);
		}

		LOG_PRINTF(LL_DEBUG,"flash_program_bytes, addr = 0x%0x, secremain = %d\r\n", writeAddr, secremain);
		/*****写入实际需要写入的内容*****/ 
		if(flash_program_bytes(writeAddr,(void *)writeBuffer,secremain) != ERRNO_OK)
		{
			LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
			return -1;
		}
		writeAddr += secremain;
		readAddr += secremain;


		/*****将剩下的数据从备份区拷贝的需要写入的区*****/ 
		if(writeAddr < (writePageAddr + FLASH_PAGE_SIZE))
		{
			for(i = 0; i < (FLASH_PAGE_SIZE - secoff - secremain)/sizeof(buffer); i++)
			{
				memset(buffer,0,sizeof(buffer));
				FlashRead(readAddr,(void *)buffer,sizeof(buffer));	//读出整个扇区的内容

				if(flash_program_bytes(writeAddr,(void *)buffer,sizeof(buffer)) != ERRNO_OK)
				{
					LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
					return -1;
				}

				readAddr += sizeof(buffer);
				writeAddr += sizeof(buffer);
			}
			if((FLASH_PAGE_SIZE - secoff - secremain) % sizeof(buffer) != 0)
			{
				memset(buffer,0,sizeof(buffer));
				FlashRead(readAddr,(void *)buffer,(FLASH_PAGE_SIZE - secoff - secremain)%sizeof(buffer));	//读出整个扇区的内容

				if(flash_program_bytes(writeAddr,(void *)buffer,(FLASH_PAGE_SIZE - secoff - secremain)%sizeof(buffer)) != ERRNO_OK)
				{
					LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
					return -1;
				}

				readAddr += (FLASH_PAGE_SIZE - secoff - secremain)%sizeof(buffer);
				writeAddr += (FLASH_PAGE_SIZE - secoff - secremain)%sizeof(buffer);
			}
		}

		if(writeNum == secremain)               	//写入结束
		{
			break;
		}

	}
}

int EepromWriteData2(uint32_t writeAddress,uint8_t* writeBuffer, uint16_t writeNum)
{
	uint32_t secpos = 0;	   	//扇区地址
	uint16_t secoff = 0;	   	//扇区内偏移地址(16位字计算)
	uint16_t secremain = 0; 	//扇区内剩余地址
 	uint32_t i = 0;
	uint32_t offaddr = 0;   	//去掉0X08000000后的地址
    uint32_t falshPageSize = 0;
    uint32_t writePageAddr = 0;
	uint32_t writeAddr = 0;
	uint32_t readAddr = 0;
	uint8_t buffer[16] = {0};

    if((writeAddress < FLASH_BASE) || ((writeAddress + writeNum) > (FLASH_BASE + CHIP_FLASH_SIZE)))
    {
		LOG_PRINTF(LL_DEBUG,"EepromWriteData:addr=0x%0x error\r\n",writeAddress);
        return -1;
    }

	while(1)
	{
		writeBuffer += secremain;  	                //指针偏移
        writeAddress += secremain;	                //写地址偏移
        writeNum -= secremain;	                	//字节数递减

		/*****将需要写入数据的区域搬迁到备份区，并擦除需要写入数据的区域*****/ 
		offaddr = writeAddress - FLASH_BASE;		//实际偏移地址
		falshPageSize = FLASH_PAGE_SIZE;
		
		secpos = offaddr/falshPageSize;				//扇区地址
		secoff = (offaddr%falshPageSize);			//在扇区内的偏移,即需要写数据的位置
		secremain = falshPageSize - secoff;			//扇区剩余空间大小
		writePageAddr = FLASH_BASE + secpos*falshPageSize;	//获取到需要写的页起始地址
		
		if(writeNum <= secremain)             		//写的数据不大于改扇区的大小，也就没有跨扇区
        {
            secremain = writeNum;
        }

		if(flash_erase_page(writePageAddr) != ERRNO_OK)        //擦除需要写的区域
		{
			LOG_PRINTF(LL_DEBUG,"flash erase flash error\r\n");
			return -1;
		}

		/*****将需要写入的数前的内容从备份区搬迁到主区*****/ 
		writeAddr = writePageAddr;
		
		LOG_PRINTF(LL_DEBUG,"flash_program_bytes, addr = 0x%0x, secremain = %d\r\n", writeAddr, secremain);
		/*****写入实际需要写入的内容*****/ 
		if(flash_program_bytes(writeAddr,(void *)writeBuffer,secremain) != ERRNO_OK)
		{
			LOG_PRINTF(LL_DEBUG,"flash_program_bytes error\r\n");
			return -1;
		}
		writeAddr += secremain;

		if(writeNum == secremain)               	//写入结束
		{
			break;
		}
	}
}
#endif